using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using System.Web;
using System.Web.Mail;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;

namespace Halide
{
	/// <summary>
	/// The Temporal class contains methods and properties for manipulating, evaluating, or displaying dates and times.
	/// </summary>
	sealed public class Temporal
	{
		private static string _version = "2007.12.14A";

		/// <summary>
		/// Return the version number of the class; read-only.
		/// </summary>
		/// <value>
		/// A string with the version number of the class.
		/// </value>
		public static string Version
		{
			get
			{
				return _version;
			}
		}

		/// <summary>
		/// No constructor is necessary.
		/// </summary>
		private Temporal()
	    {
	    }

		/// <summary>
		/// Enumeration used in the DateDiff method to specify what date/time increment to use.
		/// </summary>
		public enum DateDiffComparisonType
		{
			/// <summary>
			/// Minutes.
			/// </summary>
			minutes,
			
			/// <summary>
			/// Hours.
			/// </summary>
			hours,
			
			/// <summary>
			/// Seconds.
			/// </summary>
			seconds,
			
			/// <summary>
			/// CPU ticks.
			/// </summary>
			ticks,
			
			/// <summary>
			/// Milliseconds.
			/// </summary>
			milliseconds,
			
			/// <summary>
			/// Years.
			/// </summary>
			years,
			
			/// <summary>
			/// Quarters.
			/// </summary>
			quarters,
			
			/// <summary>
			/// Days.
			/// </summary>
			days
		}

	    /// <summary>
	    /// Compares 2 dates and determine the time interval between them.
	    /// </summary>
		/// <example>
		/// <code>
		/// double result = Halide.Temporal.DateDiff(
		///		Halide.Temporal.DateDiffComparisonType.days,
		///		startDate,
		///		endDate);
		/// </code>
		/// </example>
		/// <param name="howtocompare">String specifying comparison type.</param>
	    /// <param name="startDate">First date for comparison.</param>
	    /// <param name="endDate">Last date for comparison.</param>
		/// <returns>-1 on failure, or the date difference as a double.</returns>
		public static double DateDiff(DateDiffComparisonType howtocompare, System.DateTime startDate, System.DateTime endDate)
		{
			double diff = 0;

			try
			{
				System.TimeSpan TS = new System.TimeSpan(startDate.Ticks-endDate.Ticks);

				#region conversion options

				switch (howtocompare)
				{
					case DateDiffComparisonType.minutes:
						diff = Convert.ToDouble(TS.TotalMinutes);
						break;

					case DateDiffComparisonType.hours:
						diff = Convert.ToDouble(TS.TotalMinutes / 60);
						break;

					case DateDiffComparisonType.seconds:
						diff = Convert.ToDouble(TS.TotalSeconds);
						break;

					case DateDiffComparisonType.ticks:
						diff = Convert.ToDouble(TS.Ticks);
						break;

					case DateDiffComparisonType.milliseconds:
						diff = Convert.ToDouble(TS.TotalMilliseconds);
						break;

					case DateDiffComparisonType.years:
						diff = Convert.ToDouble(TS.TotalDays / 365);
						break;

					case DateDiffComparisonType.quarters:
						diff = Convert.ToDouble((TS.TotalDays / 365) / 4);
						break;

					default:
						diff = Convert.ToDouble(TS.TotalDays); break;
				}

				#endregion
			}
			catch
			{
				diff = -1;
			}

			return diff;
		}

		/// <summary>
		/// Enumeration used with the DateFormat method, specifying the format of the output date.
		/// </summary>
		public enum DateFormats
		{
			/// <summary>
			/// 2007-12-20
			/// </summary>
			sortable,
			
			/// <summary>
			/// 12/20/2007
			/// </summary>
			slashes,
			
			/// <summary>
			/// 12.20.2007
			/// </summary>
			dots,
			
			/// <summary>
			/// Friday; December 20, 2007
			/// </summary>
			full,
			
			/// <summary>
			/// Friday; December 20
			/// </summary>
			daily,
			
			/// <summary>
			/// Dec 1, 2007
			/// </summary>
			tidy,
			
			/// <summary>
			/// Friday
			/// </summary>
			weekday,
			
			/// <summary>
			/// Fri
			/// </summary>
			weekdayShort,
			
			/// <summary>
			/// December
			/// </summary>
			month,
			
			/// <summary>
			/// Dec
			/// </summary>
			monthShort,
			
			/// <summary>
			/// 12/2007
			/// </summary>
			corporate,
			
			/// <summary>
			/// December 20, 2007
			/// </summary>
			pressRelease,
			
			/// <summary>
			/// 12-20-2007
			/// </summary>
			standard,
			
			/// <summary>
			/// 2007-12-20T09:45:24Z
			/// </summary>
			RSS,
			
			/// <summary>
			/// Fri, 20 Dec 2007 07:01:00 GMT
			/// </summary>
			RSS2,
			
			/// <summary>
			/// Fri-Dec-20-2007
			/// </summary>
			abbreviatedFull,
			
			/// <summary>
			/// "X minutes ago", "X hours ago", "yesterday", "X days ago", "a week ago", or "on m/d/yyyy"
			/// </summary>
			friendly
		}

		/// <summary>
		/// Format a date/time variable for output.
		/// </summary>
		/// <example>
		/// <code>
		/// string result = Halide.Temporal.DateFormat(
		///		theDate,
		///		Halide.Temporal.DateFormats.friendly);
		/// </code>
		/// </example>
		/// <param name="date">DateTime variable to format.</param>
		/// <param name="format">Date format.</param>
		/// <returns>String with the date formatted as requested.</returns>
		public static string DateFormat(System.DateTime date, DateFormats format)
		{
			string thedate = string.Empty;

			try
			{
				switch (format)
				{
					case DateFormats.sortable:
						thedate = date.ToString("yyyy-MM-dd");
						break;
					case DateFormats.slashes:
						thedate = date.ToString("M/d/yyyy");
						break;
					case DateFormats.dots:
						thedate = date.ToString("M.d.yyyy");
						break;
					case DateFormats.full:
						thedate = date.ToString("dddd; MMMM d, yyyy");
						break;
					case DateFormats.daily:
                        thedate = date.ToString("dddd; MMMM d");
                        break;
                    case DateFormats.tidy:
						thedate = date.ToString("MMM d, yyyy");
						break;
					case DateFormats.weekday:
						thedate = date.ToString("dddd");
						break;
					case DateFormats.weekdayShort:
						thedate = date.ToString("ddd");
						break;
					case DateFormats.month:
						thedate = date.ToString("MMMM");
						break;
					case DateFormats.monthShort:
						thedate = date.ToString("MMM");
						break;
					case DateFormats.corporate:
						thedate = date.ToString("M/yyyy");
						break;
					case DateFormats.pressRelease:
						thedate = date.ToString("MMMM d, yyyy");
						break;
					case DateFormats.RSS:
                        thedate = date.ToUniversalTime().ToString("o");
//                        thedate = date.ToString("yyyy-MM-dd") + "T" + date.ToString("HH:mm:ss") + "Z";
						break;
					case DateFormats.RSS2:
                        thedate = date.ToUniversalTime().ToString("R");
                        break;
					case DateFormats.abbreviatedFull:
	                    thedate = date.ToString("ddd-MMM-dd-yyyy");
	                    break;
					case DateFormats.friendly:
						double days = Convert.ToInt32(DateDiff(DateDiffComparisonType.days, System.DateTime.Now, date));

						thedate = "today";

						if (Halide.Temporal.DateDiff(DateDiffComparisonType.hours, System.DateTime.Now, date) < 13 && Halide.Temporal.DateDiff(DateDiffComparisonType.hours, System.DateTime.Now, date) >= 0)
						{
							if (Halide.Temporal.DateDiff(DateDiffComparisonType.minutes, System.DateTime.Now, date) < 60 && Halide.Temporal.DateDiff(DateDiffComparisonType.minutes, System.DateTime.Now, date) > 0)
							{
								thedate = Convert.ToInt32(Halide.Temporal.DateDiff(DateDiffComparisonType.minutes, System.DateTime.Now, date)).ToString() + " minute";
								if (Convert.ToInt32(Halide.Temporal.DateDiff(DateDiffComparisonType.minutes, System.DateTime.Now, date)) != 1)
								{
									thedate += "s";
								}
								thedate += " ago";
							}
							else
							{
								thedate = Convert.ToInt32(Halide.Temporal.DateDiff(DateDiffComparisonType.hours, System.DateTime.Now, date)).ToString() + " hour";

								if (Convert.ToInt32(Halide.Temporal.DateDiff(DateDiffComparisonType.hours, System.DateTime.Now, date)) != 1)
								{
									thedate += "s";
								}
								thedate += " ago";
							}
						}
						else
						{
							if(days < 7 && days > 0)
							{
								if(days == 1)
								{
									thedate = "yesterday";
								}
								else
								{
									thedate = days.ToString() + " day";
									if(days != 1) thedate += "s";
									thedate += " ago, on " + date.ToString("M/d/yyyy");
								}
							}
							else
							{
								if(days == 7)
								{
									thedate = "a week ago";
								}
								else
								{
									thedate = "on " + date.ToString("M/d/yyyy");
								}
							}
						}
						break;
					default:
						thedate = date.ToString("M-d-yyyy");
						break;
				}
			}
			catch
			{}
			return (thedate);
		}

		/// <summary>
		/// Format a date/time variable for output.
		/// </summary>
		/// <example>
		/// <code>
		/// string result = Halide.Temporal.DateFormat(
		///		theDate,
		///		Halide.Temporal.DateFormats.friendly);
		/// </code>
		/// </example>
		/// <param name="date">DateTime variable to format.</param>
		/// <param name="format">Date format.</param>
		/// <returns>String with the date formatted as requested.</returns>
		public static string DateFormat(string date, DateFormats format)
	    {
	        return DateFormat(Convert.ToDateTime(date), format);
	    }

		/// <summary>
		/// Enumeration used to format times of day with the TimeFormat method.
		/// </summary>
		public enum TimeFormats
		{
			/// <summary>
			/// 10:23PM
			/// </summary>
			standard,
			
			/// <summary>
			/// 15:30:00
			/// </summary>
			SQLmilitary,
			
			/// <summary>
			/// 15:30
			/// </summary>
			military
		}

	    /// <summary>
		/// Format a time of day for output.
		/// </summary>
		/// <example>
		/// <code>
		/// string result = Halide.Temporal.TimeFormat(
		///		theTime,
		///		Halide.Temporal.TimeFormats.standard);
		/// </code>
		/// </example>
		/// <param name="date">Time variable to format.</param>
	    /// <param name="format">Time format.</param>
		/// <returns>String with the time of day formatted as requested.</returns>
		public static string TimeFormat(System.DateTime date, TimeFormats format)
		{
			string thedate = string.Empty;

			try
			{
				switch (format)
				{
					case TimeFormats.standard:
						thedate = date.ToString("h:mmtt");
						break;
	                case TimeFormats.SQLmilitary:
	                    thedate = date.ToString("HH:mm:ss");
	                    break;
	                case TimeFormats.military:
	                    thedate = date.ToString("HH:mm");
	                    break;
					default:
						thedate = date.ToString("h:mmtt");
						break;
				}
			}
			catch
			{}
			return (thedate);
		}

		/// <summary>
		/// Format a time of day for output.
		/// </summary>
		/// <example>
		/// <code>
		/// string result = Halide.Temporal.TimeFormat(
		///		theTime,
		///		Halide.Temporal.TimeFormats.standard);
		/// </code>
		/// </example>
		/// <param name="date">Time variable to format.</param>
		/// <param name="format">Time format.</param>
		/// <returns>String with the time of day formatted as requested.</returns>
		public static string TimeFormat(string date, TimeFormats format)
		{
			return TimeFormat(Convert.ToDateTime(date), format);
		}

		/// <summary>
		/// Enumeration used to define date intervals for the DateRange method.
		/// </summary>
	    [Flags]
	    public enum DateRangeOptions : byte
	    {
			/// <summary>
			/// Weeks
			/// </summary>
	        Week = 1,
			
			/// <summary>
			/// Months
			/// </summary>
			Month = 2,
			
			/// <summary>
			/// Quarters
			/// </summary>
			Quarter = 4,
			
			/// <summary>
			/// Years
			/// </summary>
			Year = 5
	    }

		/// <summary>
		/// Struct used to define the return value format for the DateRange method.
		/// </summary>
	    public struct DateRangeStruct
	    {
			/// <summary>
			/// Start Date is the first element.
			/// </summary>
	        public DateTime startDate;

			/// <summary>
			/// End Date is the second element.
			/// </summary>
	        public DateTime endDate;
	    }

	    /// <summary>
	    /// Returns a string array with start and end dates for a given range.
	    /// </summary>
		/// <example>
		/// If you pass the current date, and wish to know the first
		/// and last days of the week based on the current day:
		/// <code>
		/// DateRangeStruct result = Halide.Temporal.DateRange(
		///		Halide.Temporal.DateRangeOptions.Week,
		///		DateTime.Now
		///		);
		///		
		/// Response.Write ("The first day of the week is " + result.startDate.ToString() + 
		/// ", and the last day of the week is " + result.endDate.ToString());
		/// </code>
		/// </example>
		/// <param name="DRO">Enumeration value specifying which abstracted date range to evaluate. Note, weeks begin on Sunday and end on Saturday.</param>
	    /// <param name="relativeDate">Date to use as the basis for calculating the start and end date of the range.</param>
	    /// <returns>DateTimeStruct with the start and end date of the range.</returns>
	    public static DateRangeStruct DateRange(DateRangeOptions DRO, DateTime relativeDate)
	    {
	        DateTime[] retValue = { DateTime.Today, DateTime.Today };
	        DateTime myDate = relativeDate;

	        switch (DRO)
	        {
	            case DateRangeOptions.Week:

	                if(myDate.DayOfWeek > 0) myDate = myDate.AddDays(-1*Convert.ToInt32(myDate.DayOfWeek));

	                retValue[0] = myDate;
	                retValue[1] = myDate.AddDays(6);

	                break;

	            case DateRangeOptions.Month:

	                if (myDate.Day > 1) myDate = myDate.AddDays(-1 * (myDate.Day - 1));

	                retValue[0] = myDate;
	                retValue[1] = myDate.AddMonths(1);
	                retValue[1] = retValue[1].AddDays(-1);

	                break;

	            case DateRangeOptions.Quarter:

	                if (myDate.Month < 4) retValue[0] = Convert.ToDateTime("1/1/" + myDate.Year.ToString());
	                if (myDate.Month > 3 && myDate.Month < 7) retValue[0] = Convert.ToDateTime("4/1/" + myDate.Year.ToString());
	                if (myDate.Month > 6 && myDate.Month < 10) retValue[0] = Convert.ToDateTime("7/1/" + myDate.Year.ToString());
	                if (myDate.Month > 9) retValue[0] = Convert.ToDateTime("10/1/" + myDate.Year.ToString());

	                retValue[1] = retValue[0].AddMonths(3);
	                retValue[1] = retValue[1].AddDays(-1);

	                break;

	            case DateRangeOptions.Year:

	                retValue[0] = Convert.ToDateTime("1/1/" + myDate.Year.ToString());
	                retValue[1] = Convert.ToDateTime("12/31/" + myDate.Year.ToString());

	                break;
	        }

	        DateRangeStruct retVal;
	        retVal.startDate = retValue[0];
	        retVal.endDate = retValue[1];

	        return retVal;
	    }

		/// <summary>
		/// Returns a string array with start and end dates for a given range.
		/// </summary>
		/// <example>
		/// If you pass the current date, and wish to know the first
		/// and last days of the week based on the current day:
		/// <code>
		/// DateRangeStruct result = Halide.Temporal.DateRange(
		///		Halide.Temporal.DateRangeOptions.Week,
		///		DateTime.Now
		///		);
		///		
		/// Response.Write ("The first day of the week is " + result.startDate.ToString() + 
		/// ", and the last day of the week is " + result.endDate.ToString());
		/// </code>
		/// </example>
		/// <param name="DRO">Enumeration value specifying which abstracted date range to evaluate. Note, weeks begin on Sunday and end on Saturday.</param>
		/// <param name="relativeDate">Date to use as the basis for calculating the start and end date of the range.</param>
		/// <returns>DateTimeStruct with the start and end date of the range.</returns>
		public static DateRangeStruct DateRange(DateRangeOptions DRO, string relativeDate)
	    {
	        return DateRange(DRO, Convert.ToDateTime(relativeDate));
	    }

	// Outer Identify class
	}

// Outer namespace
}